# coding:utf-8
import sys
import time
import os
import xlrd
import xlwt
reload(sys)
sys.setdefaultencoding('utf8')

from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash, send_from_directory
from Database import Database
from werkzeug import secure_filename
from werkzeug.contrib.fixers import ProxyFix


# create app
SECRET_KEY = 'AFJDFA1312'
app = Flask(__name__)
app.config.from_object(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)


def add_student_from_excel(file, class_id):
    data = xlrd.open_workbook(file)
    table = data.sheets()[0]
    rows = table.nrows
    for row in range(1, rows):
        info = table.row_values(row)[1:]
        info = [info[0], info[1], info[4], info[3], info[2]]
        if not Database().add_student(info, class_id):
            return 0
    return 1


def save_score_to_excel(students, homeworks, num):
    wb = xlwt.Workbook(encoding='UTF-8')
    sheet = wb.add_sheet('成绩单')
    colcount = len(homeworks) + 5
    rowcount = len(students) + 1
    sheet.write(0, 0, '学号')
    sheet.write(0, 1, '姓名')
    sheet.write(0, 2, '学院')
    sheet.write(0, 3, '专业')
    sheet.write(0, 4, '班级')
    for col in xrange(5, colcount):
        sheet.write(0, col, homeworks[col - 5][1])
    for row in xrange(1, rowcount):
        for col in xrange(colcount):
            sheet.write(row, col, students[row - 1][col])
    wb.save('./score_file/学生成绩单_' + str(num) + '.xls')


def get_semester():
    if not session.get('semester'):
        date = time.strftime('%Y-%m')
        year = date[:5]
        month = date[5:7]
        if month >= '03' and month < '09':
            semester = year + '春'
        else:
            if month <= '02':
                year = str(int(year[:-1])-1) + '-'
            semester = year + '秋'
        session['semester'] = semester
    else:
        semester = session.get('semester')
    return semester

def get_all_semester(uid):
    if not session.get('all_semester'):
        classes = Database().get_all_classes(uid)
        if len(classes) == 0:
            session['all_semester'] = None
            return []
        else:
            # set 无法存在session中，所有需转化为list
            semesters = sorted(list(set([_class[-1] for _class in classes])), reverse=True)
            session['all_semester'] = semesters
            return semesters
    else:
        return session.get('all_semester')


def change_password(form):
    if Database().log_in(session.get('name'), form['old']):
        result = Database().change_password(
            session.get('uid'), request.form['new'])
        if result:
            flash('密码修改成功！')
        else:
            flash('密码修改时失败！')
    else:
        flash('原始密码错误！')


def add_notice(form, class_id=0):
    result = Database().add_notice(form, class_id)
    if result:
        flash('公告添加成功！')
    else:
        flash('公告添加失败！')


def show_notices(num, class_id=0):
    temp = 1  # temp 标示当前页面数
    if not num:
        num = 0
    elif num != 0:
        temp = num
        num = 4 * (num - 1)
    result, total = Database().show_notice(num, class_id)
    if total % 4 == 0:
        total = total - 1
    total = range(1, total / 4 + 2)
    return (result, total, temp)


@app.route('/')
def index():
    classes = Database().show_course()
    notice = Database().new_notice()
    return render_template('index.html', classes=classes, notice=notice)


@app.route('/notice/<int:num>')
def notice(num=0):
    result, total, aim = show_notices(num)
    return render_template('/notice.html', infos=result, total=total, aim=aim)


@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'GET':
        return redirect(url_for('index'))
    else:
        user = Database()
        result = user.log_in(request.form['name'], request.form['password'])
        if result == 0:
            flash('用户名或密码错误！')
            return redirect(url_for('index'))
        elif result == -1:
            flash('请输入用户名或密码！')
            return redirect(url_for('index'))
        else:
            session['uid'] = user.uid
            session['name'] = user.name
            if user.role == 'stu':
                session['stu_logged'] = True
                session['realname'] = user.realname
                return redirect('/student/show_homework')
            elif user.role == 'thr':
                session['thr_logged'] = True
                session['realname'] = user.realname
                return redirect('/teacher/show_homework')
            elif user.role == 'adm':
                session['adm_logged'] = True
                return redirect('/admin/show_course')


@app.route('/logout/<identity>')
def logout(identity):
    key = identity + '_logged'
    session.pop(key, None)
    if identity == 'thr':
        session.pop('semester', None)
    flash('成功退出登陆')
    return redirect(url_for('index'))


@app.route('/admin/<func>/', methods=['POST', 'GET'])
@app.route('/admin/<func>/<num>', methods=['POST', 'GET'])
@app.route('/admin/<func>/<num>-<int:num2>', methods=['POST', 'GET'])
def admin(func, num=None, num2=0):
    if not session.get('adm_logged'):
        return redirect(url_for('index'))
    elif func == 'show_course':
        courses = Database().show_course()
        return render_template('/admin/show_course.html', courses=courses)
    elif func == 'add_course':
        if request.method == 'POST':
            result = Database().add_course(request.form)
            if result:
                flash('课程添加成功！')
            else:
                flash('课程添加失败！')
        return render_template('/admin/add_course.html')
    elif func == 'del_course':
        if request.method == 'GET':
            result = Database().del_course(num)
            if result:
                flash('课程删除成功！')
            else:
                flash('课程删除失败！')
        return redirect('/admin/show_course')
    elif func == 'show_class':
        temp = 1
        if num2 != 0:
            temp = num2
            num2 = 4 * (num2 - 1)
        course = Database().get_course_name(num)
        result, total = Database().show_class(num, num2)
        if total % 4 == 0:
            total = total - 1
        total = range(1, total / 4 + 2)
        return render_template('/admin/show_class.html', infos=result,
                               course=course, total=total, course_id=num, aim=temp)
    elif func == 'add_class':
        if request.method == 'GET':
            teachers = Database().get_teachers()
            return render_template(
                '/admin/add_class.html', course=num, teachers=teachers)
        elif request.method == 'POST':
            result, class_id = Database().add_class(num, request.form)
            if result:
                flash('课堂添加成功！')
                os.system('mkdir ./uploads/' + str(class_id))
                os.system('mkdir ./uploads/' + str(class_id) + '/ppt')
                os.system('mkdir ./uploads/' + str(class_id) + '/homework')
                os.system('mkdir ./uploads/' + str(class_id) + '/image')
                folder = './uploads/' + str(class_id) + '/'
                file = request.files['excel']
                if file:
                    filename = file.filename
                    file.save(folder + filename)
                    result = add_student_from_excel(
                        folder + file.filename, class_id)
                    if result:
                        flash('学生添加成功！')
                    else:
                        flash('学生添加失败！')
            else:
                flash('课堂添加失败！')
        return redirect('/admin/show_course')
    elif func == 'del_class':
        if request.method == 'GET':
            result = Database().del_class(num)
            if result:
                path = './uploads/' + str(num)
                result = (0 == os.system('rm -rf ' + path))
            if result:
                flash('课堂删除成功！')
            else:
                flash('课堂删除失败！')
        return redirect('/admin/show_course')
    elif func == 'show_notices':
        result, total, aim = show_notices(num2)
        return render_template('/admin/show_notice.html',
                               infos=result, total=total, aim=aim)
    elif func == 'add_notice':
        if request.method == 'POST':
            add_notice(request.form)
        return render_template('/admin/add_notice.html')
    elif func == 'del_notice':
        if request.method == 'GET':
            result = Database().del_notice(num2)
            if result:
                flash('公告删除成功！')
            else:
                flash('公告删除失败！')
            return redirect('/admin/show_notices/0-%s' % num)
    elif func == 'reset_password':
        if request.method == 'POST':
            result = Database().reset_password(request.form['name'])
            if result:
                flash('密码重置成功！')
            else:
                flash('密码重置失败！')
        return render_template('/admin/reset_password.html')
    elif func == 'add_teacher':
        if request.method == 'POST':
            result = Database().add_teacher(
                request.form['name'], request.form['real_name'])
            if result:
                flash('老师 %s 添加成功！' % request.form['real_name'])
                flash('用户名：%s' % request.form['name'])
            else:
                flash('老师添加失败！')
        return render_template('/admin/add_teacher.html')
    elif func == 'change_password':
        if request.method == 'POST':
            change_password(request.form)
        return render_template('/admin/change_password.html')


@app.route('/teacher/<func>/', methods=['POST', 'GET'])
@app.route('/teacher/<int:num>/<func>/', methods=['POST', 'GET'])
@app.route('/teacher/<int:num>/<func>/<int:num2>', methods=['POST', 'GET'])
def teacher(func, num=None, num2=None):
    if not session.get('thr_logged'):
        return redirect(url_for('index'))
    else:
        semester = get_semester()
        user_id = session.get('uid')
        db = Database()
        classes = db.get_classes(user_id, semester)
        realname = session['realname']
        semesters = get_all_semester(user_id)
        if not semesters:
            flash("该教师尚无课程！")
            return redirect(url_for('index'))
        if not classes:
            return render_template('/teacher/no_class.html', classes=classes, name=realname, semesters=semesters)
        if not num:
            num = int(classes[0][0])
        if func == 'change_semester':
            session['semester'] = semesters[num2]
            return redirect('/teacher/show_homework')
        elif func == 'show_homework':
            homeworks, total = db.show_homework(num)
            return render_template('/teacher/show_homework.html', classes=classes,
                                   aim=num, homeworks=homeworks, total=total, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'show_homework_detail':
            homework = db.show_homework_detail(num2)
            return render_template('/teacher/show_homework_detail.html',
                                   classes=classes, aim=num, homework=homework, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'change_homework':
            if request.method == 'POST':
                if not request.form['deadline']:
                    flash('请输入截止时间！')
                result = db.change_homework_detail(request.form, num2)
                if result:
                    flash('修改作业成功！')
                else:
                    flash('修改作业失败！')
            homework = db.show_homework_detail(num2)
            return render_template('teacher/change_homework.html',
                                   classes=classes, aim=num, homework=homework, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'del_homework':
            done = db.del_homework(num2)
            if done:
                path = './uploads/' + str(num) + '/homework/' + str(num2)
                os.system('rm -rf ' + path)
            return redirect('/teacher/' + str(num) + '/show_homework/')
        elif func == 'students':
            done, students = db.show_student_homework(num, num2)
            return render_template('/teacher/student.html', classes=classes,
                                   aim=num, done=done, students=students, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'score':
            if request.method == 'POST':
                error = db.score(num2, request.form)
                if not error:
                    flash('打分成功！')
                else:
                    flash('打分失败！')
                    flash(error)
            students = db.show_student_done_homework(num2)
            return render_template('/teacher/score.html', classes=classes,
                                   aim=num, students=students, homework=num2, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'show_score':
            students, homeworks = db.show_score(num)
            return render_template('/teacher/show_score.html', classes=classes,
                                   aim=num, students=students, homeworks=homeworks, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'score_excel':
            students, homeworks = db.show_score_excel(num)
            save_score_to_excel(students, homeworks, num)
            return send_from_directory(
                './score_file/', '学生成绩单_' + str(num) + '.xls')
        elif func == 'download_homework':
            folder = './uploads/' + str(num) + '/homework/' + str(num2)
            os.system('rm ' + folder + '/homework_' + str(num2) + '.zip')
            os.system('zip -r ' + folder + '/homework_' + str(num2) + ' ' + folder + '/*')
            return send_from_directory(
                folder, 'homework_' + str(num2) + '.zip')
        elif func == 'add_homework':
            if request.method == 'POST':
                if not request.form['deadline']:
                    flash('请输入截止时间！')
                else:
                    result, class_id = db.add_homework(request.form, num)
                    folder = './uploads/' + \
                        str(num) + '/homework/' + str(class_id)
                    os.system('mkdir ' + folder)
                    if result:
                        flash('作业添加成功！')
                    else:
                        flash('作业添加失败！')
            return render_template(
                '/teacher/add_homework.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'show_discussion':
            temp = 1  # temp 标示当前页面数
            if not num2:
                num2 = 0
            elif num2 != 0:
                temp = num2
                num2 = 4 * (num2 - 1)
            discussions, total = db.show_discussion(num2, num)
            if total % 4 == 0:
                total = total - 1
            total = range(1, total / 4 + 2)
            infos = []
            for discussion in discussions:
                info = list(discussion)
                info.append(Database().get_realname(discussion[2]))
                infos.append(info)
            return render_template('/teacher/show_discussion.html', classes=classes,
                                   aim=num, infos=infos, total=total, now=temp, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'show_discussion_detail':
            session['head_id'] = num2
            details = db.show_discussion_detail(num2)
            infos = []
            for detail in details:
                info = list(detail)
                info.append(Database().get_realname(detail[2]))
                infos.append(info)
            return render_template("/teacher/show_discussion_detail.html",
                                   classes=classes, aim=num, infos=infos, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'add_discussion':
            if request.method == 'POST':
                folder = './uploads/' + str(num) + '/image/'
                app.config['MAX_CONTENT_LENGTH'] = 6 * 1024 * 1024
                if num2 is None:
                    num2 = 1
                allowed_file = set(['jpg', 'png'])
                file = request.files['image']
                wrong = 0
                if file:
                    if file.filename.rsplit('.', 1)[1] in allowed_file:
                        path = folder + str(user_id) + file.filename
                        file.save(path)
                        url = '/' + str(num) + '/image/' + \
                            str(user_id) + file.filename
                    else:
                        wrong = 1
                        flash('图片不符合规范！')
                else:
                    url = '0'
                if not wrong:
                    result = Database().add_discussion(
                        request.form['content'], url, num, user_id, num2)
                    if result:
                        flash('讨论添加成功！')
                    else:
                        flash('讨论添加失败！')
            if num2 == 1 or request.method == 'GET':
                return render_template(
                    '/teacher/add_discussion.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
            else:
                class_id = session.get('head_id')
                session.pop('head_id', None)
                return redirect('/teacher/' + str(num) +
                                '/show_discussion_detail/' + str(class_id))
        elif func == 'del_discussion':
            result = Database().del_discussion(num2)
            if result:
                flash('讨论删除成功！')
            else:
                flash('讨论删除失败！')
            return redirect('/teacher/' + str(num) + '/show_discussion')
        elif func == 'show_ppt':
            files = Database().show_file(num, 'ppt')
            return render_template(
                '/teacher/show_ppt.html', classes=classes, aim=num, files=files, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'add_ppt':
            if request.method == 'POST':
                folder = './uploads/' + str(num) + '/ppt/'
                file = request.files['ppt']
                if file:
                    filename = file.filename
                    file.save(folder + filename)
                    result = Database().add_file(
                        request.form['title'], folder + filename, 'ppt', num, user_id)
                    if result:
                        flash('文件添加成功！')
                    else:
                        flash('文件添加失败！')
            return render_template(
                '/teacher/add_ppt.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'del_ppt':
            url = db.get_file_path(num2)
            if 0 == os.system('rm \'' + url + '\''):
                db.del_file(num2)
            return redirect('/teacher/' + str(num) + '/show_ppt/')
        elif func == 'show_students':
            students = Database().show_students(num)
            return render_template('/teacher/show_students.html',
                                   classes=classes, aim=num, students=students, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'manage_students':
            return render_template(
                '/teacher/manage_students.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'add_student_from_excel':
            if request.method == 'POST':
                folder = './uploads/' + str(num) + '/'
                file = request.files['excel']
                if file:
                    filename = file.filename
                    file.save(folder + filename)
                    result = add_student_from_excel(folder + filename, num)
                    if result:
                        flash('学生添加成功！')
                    else:
                        flash('学生添加失败！')
                return render_template(
                    '/teacher/manage_students.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'add_student':
            if request.method == 'POST':
                form = request.form
                info = [
                    form['ID'],
                    form['name'],
                    form['class'],
                    form['major'],
                    form['college']]
                result = Database().add_student(info, num)
                if result:
                    flash('学生添加成功！')
                else:
                    flash('学生添加失败！')
            return render_template(
                '/teacher/manage_students.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'del_student':
            if request.method == 'POST':
                result = Database().del_student(request.form['ID'])
                if result:
                    flash('学生删除成功！')
                else:
                    flash('学生删除失败！')
            return render_template(
                '/teacher/manage_students.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'change_student_info':
            if request.method == 'POST':
                form = request.form
                info = [
                    form['ID'],
                    form['name'],
                    form['class'],
                    form['major'],
                    form['college']]
                result = Database().change_student(info)
                if result:
                    flash('信息修改成功！')
                else:
                    flash('信息修改失败！')
            return render_template(
                '/teacher/manage_students.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'show_notice':
            result, total, now = show_notices(num2, num)
            return render_template('/teacher/show_notice.html', classes=classes,
                                   total=total, aim=num, infos=result, now=now, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'add_notice':
            if request.method == 'POST':
                add_notice(request.form, num)
            return render_template(
                '/teacher/add_notice.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)
        elif func == 'del_notice':
            if request.method == 'GET':
                result = Database().del_notice(num2)
                if result:
                    flash('公告删除成功！')
                else:
                    flash('公告删除失败！')
            return redirect('/teacher/' + str(num) + '/show_notice')
        elif func == 'change_password':
            if request.method == 'POST':
                change_password(request.form)
            return render_template(
                '/teacher/change_password.html', classes=classes, aim=num, name=realname, semesters=semesters, now_semester=semester)


@app.route('/student/<func>/', methods=['POST', 'GET'])
@app.route('/student/<int:num>/<func>/', methods=['POST', 'GET'])
@app.route('/student/<int:num>/<func>/<int:num2>', methods=['POST', 'GET'])
def student(func, num=None, num2=None):
    if not session.get('stu_logged'):
        return redirect(url_for('index'))
    else:
        semester = get_semester()
        db = Database()
        user_id = session.get('uid')
        user_name = session.get('name')
        user_realname = session.get('realname')
        classes = db.get_student_classes(user_name, semester)
        if classes and not num:
            num = int(classes[0][0])
        if not classes:
            flash('该学生本学期无课！')
            return redirect(url_for('index'))
        elif func == 'show_homework':
            homeworks = db.show_homeworks_student(num, user_id)
            return render_template('/student/show_homework.html', classes=classes,
                                   aim=num, homeworks=homeworks, name=user_realname)
        elif func == 'show_homework_detail':
            if request.method == 'GET':
                homework, dead = db.show_homework_detail_student(num2)
                return render_template('/student/show_homework_detail.html', classes=classes,
                                       aim=num, homework=homework, dead=dead, name=user_realname)
        elif func == 'add_homework':
            if request.method == 'POST':
                folder = './uploads/' + \
                    str(num) + '/homework/' + str(num2) + '/'
                app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024
                allowed_file = set(['zip'])
                file = request.files['work']
                wrong = 0
                if file:
                    if file.filename.rsplit('.', 1)[1] in allowed_file:
                        path = folder + session['name'] + '_' + file.filename
                        file.save(path)
                        # 有时上传文件会莫名消失， 再次确认文件是否在服务器上
                        if os.popen("find %s -name '%s'" % (folder[:-1], session['name'] + '_' + file.filename)).read()[:-1] != path:
                            flash('上传失败！')
                            wrong = 1
                    else:
                        wrong = 1
                        flash('文件不符合规范！')
                else:
                    flash("请选择上传文件！")
                    wrong = 1
                if wrong == 0:
                    old = Database().get_homework_student(user_id, num2)
                    if old:
                        if old != path:
                            os.system('rm ' + old)
                        result = Database().add_homework_student(user_id, num2, path, 'UPDATE')
                    else:
                        result = Database().add_homework_student(user_id, num2, path, 'INSERT')
                    if result:
                        flash('作业上传成功！')
                    else:
                        flash('作业上传失败！')
                return redirect('student/' + str(num) +
                                '/show_homework_detail/' + str(num2))
        elif func == 'show_ppt':
            files = Database().show_file(num, 'ppt')
            return render_template(
                '/student/show_ppt.html', classes=classes, aim=num, files=files, name=user_realname)
        elif func == 'show_discussion':
            temp = 1  # temp 标示当前页面数
            if not num2:
                num2 = 0
            elif num2 != 0:
                temp = num2
                num2 = 4 * (num2 - 1)
            discussions, total = Database().show_discussion(num2, num)
            if total % 4 == 0:
                total = total - 1
            total = range(1, total / 4 + 2)
            infos = []
            for discussion in discussions:
                info = list(discussion)
                info.append(Database().get_realname(discussion[2]))
                infos.append(info)
            return render_template('/student/show_discussion.html', classes=classes,
                                   aim=num, infos=infos, total=total, now=temp, name=user_realname)
        elif func == 'show_discussion_detail':
            session['head_id'] = num2
            details = Database().show_discussion_detail(num2)
            infos = []
            for detail in details:
                info = list(detail)
                info.append(Database().get_realname(detail[2]))
                infos.append(info)
            return render_template("/student/show_discussion_detail.html",
                                   classes=classes, aim=num, infos=infos, name=user_realname)
        elif func == 'add_discussion':
            if request.method == 'POST':
                folder = './uploads/' + str(num) + '/image/'
                app.config['MAX_CONTENT_LENGTH'] = 6 * 1024 * 1024
                if num2 is None:
                    num2 = -1
                allowed_file = set(['jpg', 'png'])
                file = request.files['image']
                wrong = 0
                if file:
                    if file.filename.rsplit('.', 1)[1] in allowed_file:
                        path = folder + str(user_id) + file.filename
                        file.save(path)
                        url = '/' + str(num) + '/image/' + \
                            str(user_id) + file.filename
                    else:
                        wrong = 1
                        flash('图片不符合规范！')
                else:
                    url = '0'
                if not wrong:
                    result = Database().add_discussion(
                        request.form['content'], url, num, user_id, num2)
                    if result:
                        flash('讨论添加成功！')
                    else:
                        flash('讨论添加失败！')
            if num2 == 1 or request.method == 'GET':
                return render_template(
                    '/student/add_discussion.html', classes=classes, aim=num, name=user_realname)
            else:
                class_id = session.get('head_id')
                session.pop('head_id', None)
                return redirect('/student/' + str(num) +
                                '/show_discussion_detail/' + str(class_id))
        elif func == 'show_notice':
            result, total, now = show_notices(num2, num)
            return render_template('/student/show_notice.html', classes=classes,
                                   total=total, aim=num, infos=result, now=now, name=user_realname)
        elif func == 'change_password':
            if request.method == 'POST':
                change_password(request.form)
            return render_template(
                '/student/change_password.html', classes=classes, aim=num, name=user_realname)


@app.route('/download/<func>/<int:num>/<filename>')
def download(func, num, filename=None):
    if func == 'ppt':
        return send_from_directory('./uploads/' + str(num) + '/ppt/', filename)


@app.route('/<int:num>/image/<filename>')
def show_img(num, filename):
    return send_from_directory('./uploads/' + str(num) + '/image/', filename)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)
